﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Web;
using System.Net;

namespace TUDifier_2
{
    
    public partial class mainForm : Form
    {
        //Declarations and such
        string xmlLocation = null, saveLocation = null;
        int updatesComplete = 0, DownloadSize = 0, numberOfSelected = 0;
        delegate void AddLogItem(string text);
        delegate void setStatus(string statusText);
        delegate void progressStatus(double proStat);
        delegate void ListViewRetrieve(int index);
        delegate void selectedListViewRetrieve(int index);
        ListViewItem RecievedListItem;
        bool aSyncCancelPending = false;
        public struct ListViewSelected
        {
            public bool selected;
            public int index;
        }

        public ListViewSelected[] selectedListView = new ListViewSelected[1000];



        public ListView getListView
        {
            get { return gamesListView; }
            set { gamesListView = value; }
        }

        public mainForm()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.Text = "TUDifier " + this.ProductVersion.Substring(0, this.ProductVersion.Length - 4);

            AddItemtoLog(this.Text);
            AddItemtoLog("   by Scuba156(XeLove)");
            AddItemtoLog("   Click 'Open' to start");

            for (int i = 0; i < 1000; i++)
            {
                selectedListView[i].index = -1;
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        public void setNewStatus(String statusText)
        {
            if (this.statusStrip1.InvokeRequired)
            {
                setStatus d = new setStatus(setNewStatus);
                this.Invoke(d, new object[] { statusText });
            }
            else
            {
                this.statusLabel.Text = statusText;
            }

        }

        public void Setprogmax(double Prog)
        {
            if (this.statusStrip1.InvokeRequired)
            {
                progressStatus d = new progressStatus(Setprogmax);
                this.Invoke(d, new object[] { Prog });
            }
            else
            {
                //this.DownloadSizeLabel.Text = (Convert.ToDouble(Prog) / 1048576).ToString("N") + " Mb  |";
            }

        }

        public void SetprogVal(double Val)
        {
            if (this.statusStrip1.InvokeRequired)
            {
                progressStatus d = new progressStatus(SetprogVal);
                this.Invoke(d, new object[] { Val });
            }
            else
            {
                this.DownloadProgressBar.Value = int.Parse(Math.Truncate(Val).ToString());
                //this.PercentageLabel.Text = int.Parse(Math.Truncate(Val).ToString()).ToString() + "% Complete  |";
                this.statusStrip1.Refresh();
            }

        }

        public void contentXMLRead(bool fsd2)
        {
            StreamReader oRead = File.OpenText(xmlLocation);

            string xmlStream = oRead.ReadToEnd();
            oRead.Close();

            if (xmlStream.Contains("&"))
            {
                xmlStream = xmlStream.Replace("&", "and");
            }

            File.WriteAllText("temp_content.xml", xmlStream);
            XmlDocument xDoc = new XmlDocument();
            xDoc.Load("temp_content.xml");

            if (xDoc.DocumentElement.Name == "freestyle")
            {

                if (fsd2 == false)
                {
                    XmlNodeList TitleID = xDoc.GetElementsByTagName("id");
                    XmlNodeList GameName = xDoc.GetElementsByTagName("title");
                    XmlNodeList MediaID = xDoc.GetElementsByTagName("mediaid");
                    int Count = TitleID.Count - 1;

                    for (int index = 0; index <= Count; index++)
                    {
                        int MediaIDInt;
                        MediaIDInt = Convert.ToInt32(MediaID.Item(index).InnerText);

                        gamesListView.Items.Add(GameName.Item(index).InnerText);
                        gamesListView.Items[index].SubItems.Add(TitleID.Item(index).InnerText.ToUpper());
                        gamesListView.Items[index].SubItems.Add(MediaIDInt.ToString("X"));
                        AddItemtoLog("Found " + GameName.Item(index).InnerText);
                    }
                }
                else
                {
                    XmlNodeList TitleID = xDoc.GetElementsByTagName("id");
                    XmlNodeList GameType = xDoc.GetElementsByTagName("type");
                    XmlNodeList Game = xDoc.GetElementsByTagName("game");
                    int Count = Game.Count - 1;

                    int ItemCount = 0;

                    for (int index = 0; index <= Count; index++)
                    {
                        int GameTypeID = Convert.ToInt16(Game.Item(index).Attributes.Item(0).InnerText);
                        if ((GameTypeID == 0) || (GameTypeID == 1) || (GameTypeID == 2))
                        {
                            //if (Form1.getnames == true)
                            //{
                            //    Form1.GamesList.Items.Add(GetGameName(Game.Item(index).Attributes.Item(1).InnerText.ToUpper()));
                            //}
                            //else
                            //{
                            gamesListView.Items.Add("");
                            //}
                            gamesListView.Items[ItemCount].SubItems.Add(Game.Item(index).Attributes.Item(1).InnerText.ToUpper());
                            gamesListView.Items[ItemCount].SubItems.Add(GetGameType(Convert.ToInt16(Game.Item(index).Attributes.Item(0).InnerText)));
                            AddItemtoLog("Found " + Game.Item(index).Attributes.Item(1).InnerText.ToUpper());
                            ItemCount++;
                        }
                    }
                }
                downloadButton.Enabled = true;
                selectAllToolStripMenuItem.Enabled = true;
                invertSelectionToolStripMenuItem.Enabled = true;
            }
            else
            {
                //return error
            }
        }

        public static string GetGameType(int GameTypeNumber)
        {
            string returnValue = "UNKNOWN";

            switch (GameTypeNumber)
            {
                case 0:
                    returnValue = "XBLA";
                    break;
                case 1:
                    returnValue = "XBOX 360";
                    break;
                case 2:
                    returnValue = "XBOX 1";
                    break;
                case 3:
                    returnValue = "HOMEBREW";
                    break;
                case 4:
                    returnValue = "EMULATOR";
                    break;
                default:
                    returnValue = "UNKNOWN";
                    break;
            }

            return returnValue;
        }

        private void openButton_Click(object sender, EventArgs e)
        {
            FSDSelectorDialog();
        }

        private void FSDSelectorDialog()
        {
            SelectionDialog SelectFSD = new SelectionDialog("FreeStyle Dash 1.20", "FreeStyle Dash 2.0 alpha");
            
            if (SelectFSD.ShowDialog() == DialogResult.OK)
            {
                if (SelectFSD.selection == 1)
                {//FSD1.20
                    openFileDialog1.Title = "Open FSD 1.20 content.xml";
                    openFileDialog1.FileName = "content.xml";
                    if (openFileDialog1.ShowDialog() == DialogResult.OK)
                    {
                        
                        xmlLocation = openFileDialog1.FileName;
                        gamesListView.Items.Clear();
                        contentXMLRead(false);

                        gamesListView.Columns[2].Text = "Media ID";
                        gamesListView.Refresh();
                    }
                }
                else
                {//FSD 2
                    openFileDialog1.Title = "Open FSD 2.0 alpha fsd2content.xml";
                    openFileDialog1.Filter = "Xml Files|*.xml|Any Files|*.*";
                    openFileDialog1.FileName = "fsd2content.xml";
                    if (openFileDialog1.ShowDialog() == DialogResult.OK)
                    {
                        xmlLocation = openFileDialog1.FileName;
                        gamesListView.Items.Clear();
                        contentXMLRead(true);

                        gamesListView.Columns[2].Text = "Game Type";
                        gamesListView.Refresh();
                    }
                }
            }

        }
        

        private void AddItemtoLog(string textToAdd)
        {

            if (this.logListBox.InvokeRequired)
            {
                AddLogItem d = new AddLogItem(AddItemtoLog);
                this.Invoke(d, new object[] { textToAdd });
            }
            else
            {
                this.logListBox.Items.Add(textToAdd);
                this.logListBox.TopIndex = this.logListBox.Items.Count - 1;
            }
        }

        private void GetSelectedItem(int index)
        {

            if (this.gamesListView.InvokeRequired)
            {
                selectedListViewRetrieve d = new selectedListViewRetrieve(GetListItem);
                this.Invoke(d, new object[] { index });
            }
            else
            {
                
                if (gamesListView.Items[index].Selected)
                {
                    selectedListView[numberOfSelected].selected = true;
                    selectedListView[numberOfSelected].index = index;
                    //selectedListView.Items[selectedListView.Items.Count - 1].Tag = index;
                    numberOfSelected += 1;
                }
            }
        }

        private void GetListItem(int index)
        {
            
            if (this.gamesListView.InvokeRequired)
            {
                ListViewRetrieve d = new ListViewRetrieve(GetListItem);
                this.Invoke(d, new object[] { index });
            }
            else
            {
                RecievedListItem = gamesListView.Items[index];
                
            }
            
        }
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FSDSelectorDialog();
        }

        private void downloadButton_Click(object sender, EventArgs e)
        {
            selectedListView[0].selected = false;

            if (updateAllBackgroundWorker.IsBusy || updateSelectedBackgroundWorker.IsBusy)
            {

                    if (updateAllBackgroundWorker.IsBusy)
                    {
                        updateAllBackgroundWorker.CancelAsync();
                        aSyncCancelPending = updateAllBackgroundWorker.CancellationPending;
                        downloadButton.Text = "Cancelling...";
                        downloadButton.Enabled = false;
                        AddItemtoLog("Cancelling update");
                    }
                    else if (updateSelectedBackgroundWorker.IsBusy)
                    {
                        updateSelectedBackgroundWorker.CancelAsync();
                        aSyncCancelPending = updateSelectedBackgroundWorker.CancellationPending;
                        downloadButton.Text = "Cancelling...";
                        downloadButton.Enabled = false;
                        AddItemtoLog("Cancelling update");
                    }
            }
            //MessageBox.Show("A download process is already running, please wait until completed", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            else
            {
                SelectionDialog downloadTypeDialog = new SelectionDialog("Update Selected Only", "Update All");
                if (downloadTypeDialog.ShowDialog() == DialogResult.OK)
                {
                    selectedListView[0].selected = false;
                    if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
                    {
                        for (int i = 0; i < 1000; i++)
                        {
                            selectedListView[i].selected = false;
                            selectedListView[i].index = -1;
                        }

                        saveLocation = folderBrowserDialog1.SelectedPath;

                        if (!saveLocation.EndsWith("\\"))
                            saveLocation = saveLocation + "\\";
                        if (downloadTypeDialog.selection == 1)
                        {//update selected only
                            updatesComplete = 0;
                            int n = 0;
                            for (int count = 0; count < gamesListView.Items.Count; count++)
                            {

                                if (gamesListView.Items[count].Selected)
                                {
                                    //selectedListView.Items.Add(gamesListView.Items[count].SubItems[1].Text);//addToList(count));
                                    //selectedListView.Items.Add("1");
                                    selectedListView[n].index = count;
                                    selectedListView[n].selected = true;
                                    numberOfSelected += 1;
                                    //addToList(count);

                                }
                                n++;
                            }
                            //add one to selected 
                            updateSelectedBackgroundWorker.RunWorkerAsync();
                            downloadButton.Text = "&Cancel";
                        }
                        else
                        {//update all
                            updatesComplete = 0;
                            updateAllBackgroundWorker.RunWorkerAsync();
                            downloadButton.Text = "&Cancel";
                        }
                    }
                }
            }
        }


        private ListViewItem addToList(int count)
        {
            ListViewItem selected;
            selected = gamesListView.Items[count];
            //selected.Add(gamesListView.Items[count].SubItems[0].Text);
            //selected.Items[numberOfSelected].SubItems.Add(gamesListView.Items[count].SubItems[1].Text);
            //selected.Items[numberOfSelected].SubItems.Add(gamesListView.Items[count].SubItems[2].Text);
            selected.Tag = count;
            numberOfSelected += 1;
            return selected;
        }
        private void updateAllBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            string titleID = null;

            if (!Directory.Exists(saveLocation))
                Directory.CreateDirectory(saveLocation);

            for(int count = 0; count < gamesListView.Items.Count; count++)
            {
                if (!updateAllBackgroundWorker.CancellationPending)
                {
                    doDownloadStuff(titleID, count);
                }
                else
                {
                    e.Cancel = true;
                }
            }
        }

        private void doDownloadStuff(string titleID, int count)
        {
            GetListItem(count);
            titleID = RecievedListItem.SubItems[1].Text;
            setNewStatus("Checking updates for " + titleID);
            if (DownloadtempFile("http://marketplace.jqe360.com.nyud.net/index.php?details&id=" + titleID, "tempFile")) //if download completes
            {
                StreamReader readfile = new StreamReader("tempFile");
                string fileData = readfile.ReadToEnd();
                if (fileData.Contains("/./dlc/" + titleID + "/000B0000/"))
                {
                    int first = fileData.IndexOf("/dlc/" + titleID + "/000B0000/");
                    int second = fileData.IndexOf("\"", first);
                    string link = fileData.Substring(first, second - first);
                    string fileName = fileData.Substring(first + 23, second - first - 23);
                    if (!File.Exists(saveLocation + fileName))
                    {
                        setNewStatus("Downloading " + fileName);
                        if (DownloadFile("http://marketplace.jqe360.com.nyud.net" + link, saveLocation + fileName))
                        {
                            AddItemtoLog(fileName + " downloaded successfully");
                            updatesComplete += 1;
                        }
                        SetprogVal(0);
                    }
                    else
                    {
                        AddItemtoLog(titleID + " already at the latest version");
                    }
                }
                else
                {
                    AddItemtoLog("No updates found for " + titleID);
                }
                readfile.Close();

                if (File.Exists("tempFile"))
                    File.Delete("tempFile");
            }
        }

        private void updateAllBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            System.Media.SystemSounds.Exclamation.Play();
            if (e.Cancelled)
                AddItemtoLog("Download was cancelled!");
            AddItemtoLog("Updating has Finished!");
            AddItemtoLog(updatesComplete + " updates successfully downloaded!");
            SetprogVal(0);
            setNewStatus("Idle");
            downloadButton.Enabled = true;
            downloadButton.Text = "&Download";
            aSyncCancelPending = false;
        }

        public bool DownloadtempFile(string httpPath, string Destination)
        {
            try
            {
                // Create a WebClient instance
                WebClient myClient = new WebClient();
                // Open a stream that references the page

                WebClient wc = new WebClient();

                //byte[] b = wc.DownloadData(httpPath);
                Stream response = wc.OpenRead(httpPath);

                // show the response headers
                WebHeaderCollection headers = wc.ResponseHeaders;
                //Console.WriteLine("Response headers:");
                //for (int i = 0; i < headers.Count; i++)
                //{
                //    Console.WriteLine("{0} = {1}", headers.GetKey(i), headers.Get(i));
                //}
                string headType = null;
                int headLimit = headers.Keys.Count - 1;
                int headKey = -1;

                while (headKey < headLimit)
                {
                    headKey += 1;
                    headType = headers.GetKey(headKey);
                    if (headType == "Content-Length")
                        break;
                }
                if (headType == "Content-Length")
                {
                    DownloadSize = Convert.ToInt32(headers.Get(headKey));
                }
                //SetprogVal(0);
                //Setprogmax(DownloadSize);
                
                FileStream fs = new FileStream(Destination, FileMode.Create);
                byte[] buffer = new byte[1024];
                long RunningTotal = 0;
                int bytesRead = -1;
                int byteCount = -1;
                while (bytesRead != 0)
                {
                    if (aSyncCancelPending == true)
                    {
                        fs.Close();
                        response.Close();
                        File.Delete(Destination);
                        return false;
                    }
                    else
                    {
                        byteCount += 1;
                        bytesRead = response.Read(buffer, 0, buffer.Length);
                        RunningTotal += 1;

                        //if (byteCount == 8)
                        //{
                        //    SetprogVal(+1);
                        //    byteCount = 0;
                        //}
                        //Console.WriteLine("{0} bytes read", bytesRead);
                        if (bytesRead > 0)
                            fs.Write(buffer, 0, bytesRead);
                        //Calculate progress
                        double dIndex = (double)fs.Length;
                        double dTotal = (double)DownloadSize;
                        double dProgressPercentage = (dIndex / dTotal);
                        int iProgressPercentage = (int)(dProgressPercentage * 100);
                    }
                    //SetprogVal(iProgressPercentage);
                }
                fs.Close();
                response.Close();

                //response.Close();
                //wc.DownloadFile(httpPath, Destination);
                return true;
            }
            catch (Exception ex)
            {
                AddItemtoLog("Error: " + ex.Message);
                return false;
            }
        }

        public bool DownloadFile(string httpPath, string Destination)
        {
            try
            {
                // Create a WebClient instance
                WebClient myClient = new WebClient();
                // Open a stream that references the page

                WebClient wc = new WebClient();

                //byte[] b = wc.DownloadData(httpPath);
                Stream response = wc.OpenRead(httpPath);

                // show the response headers
                WebHeaderCollection headers = wc.ResponseHeaders;

                string headType = null;
                int headLimit = headers.Keys.Count - 1;
                int headKey = -1;

                while (headKey < headLimit)
                {
                    headKey += 1;
                    headType = headers.GetKey(headKey);
                    if (headType == "Content-Length")
                        break;
                }
                if (headType == "Content-Length")
                {
                    DownloadSize = Convert.ToInt32(headers.Get(headKey));
                }
                SetprogVal(0);
                Setprogmax(DownloadSize);
                setNewStatus(statusLabel.Text + "  |  " + ((double)DownloadSize / 1048576).ToString("N") + " Mb");

                FileStream fs = new FileStream(Destination, FileMode.Create);
                byte[] buffer = new byte[1024];
                long RunningTotal = 0;
                int bytesRead = -1;
                int byteCount = -1;
                while (bytesRead != 0)
                {
                    if (aSyncCancelPending == true)
                    {
                        fs.Close();
                        response.Close();
                        File.Delete(Destination);
                        return false;
                    }
                    else
                    {
                        byteCount += 1;
                        bytesRead = response.Read(buffer, 0, buffer.Length);
                        RunningTotal += 1;

                        if (bytesRead > 0)
                            fs.Write(buffer, 0, bytesRead);

                        //Calculate progress
                        double dIndex = (double)fs.Length;
                        double dTotal = (double)DownloadSize;
                        double dProgressPercentage = (dIndex / dTotal);
                        int iProgressPercentage = (int)(dProgressPercentage * 100);

                        SetprogVal(iProgressPercentage);
                    }
                }
                fs.Close();
                response.Close();

                //response.Close();
                //wc.DownloadFile(httpPath, Destination);
                return true;
            }
            catch (Exception ex)
            {
                AddItemtoLog("Error: " + ex.Message);
                return false;
            }
        }

        private void updateSelectedBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            string titleID = null;
            
            
            if (!Directory.Exists(saveLocation))
                Directory.CreateDirectory(saveLocation);

            //for (int count = 0; count < gamesListView.Items.Count; count++)
            //{
            //    if (!updateSelectedBackgroundWorker.CancellationPending)
            //    {
            //        GetSelectedItem(count);
            //    }
            //    else
            //    {
            //        e.Cancel = true;
            //    }
            //}

            if (numberOfSelected == 0)
            {
                AddItemtoLog("No games selected to update, please select the games");
                AddItemtoLog("you wish to update and try again, or alternatively");
                AddItemtoLog("use the 'Update All' button.");

            }
            else
            {
                for (int i = 0; i < 1000; i++)
                {
                    if (!updateSelectedBackgroundWorker.CancellationPending)
                    {
                        if(selectedListView[i].selected == true)
                            doDownloadStuff(titleID, selectedListView[i].index);
                    }
                    else
                    {
                        e.Cancel = true;
                    }
                }
            }
        }

        private void updateSelectedBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            System.Media.SystemSounds.Exclamation.Play();
            if (e.Cancelled)
                AddItemtoLog("Download was cancelled!");
            AddItemtoLog("Updating has Finished!");
            AddItemtoLog(updatesComplete + " updates successfully downloaded!");
            SetprogVal(0);
            setNewStatus("Idle");
            downloadButton.Enabled = true;
            downloadButton.Text = "&Download";
            aSyncCancelPending = false;
        }

        private void selectAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < gamesListView.Items.Count; i++)
            {
                gamesListView.Items[i].Selected = true;
            }
            gamesListView.Focus();
        }

        private void invertSelectionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < gamesListView.Items.Count; i++)
            {
                if (gamesListView.Items[i].Selected == true)
                    gamesListView.Items[i].Selected = false;
                else
                    gamesListView.Items[i].Selected = true;
            }
            gamesListView.Focus();
        }

        private void findToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bool formOpen = false;
            foreach (Form a in Application.OpenForms)
            {
                if (a is FindForm)
                {
                    a.Focus();
                    formOpen = true;
                    break;

                }
            }
            if (formOpen == false)
            {
                FindForm Search = new FindForm();
                Search.gamesList = this.gamesListView;
                Search.Show();
            }
        }

        public void displayFound(int index)
        {
            if (index != -1)
            {
                gamesListView.Items[index].Selected = true;
                gamesListView.Focus();
                gamesListView.EnsureVisible(index);
            }
        }


    }

}
